using System;

namespace Geometry
{
	/// <summary>
	/// 
	/// </summary>
	public struct Vector2D
	{
		public double X;
		public double Y;

		public Vector2D (Point2D p)
		{
			X = p.x;
			Y = p.y;
		}

		public Vector2D (Point2D from, Point2D to)
		{
			X = to.x - from.x;
			Y = to.y - from.y;
		}

		public Vector2D (double x, double y)
		{
			X = x;
			Y = y;
		}


		/// <summary>
		/// Creates a normalized vector in the 'angle' direction
		/// </summary>
		/// <param name="angle"></param>
		public Vector2D (double angle)
		{
			X = Math.Cos(angle);
			Y = Math.Sin(angle);
		}

		public void Normalize ()
		{
			double len = Length;
			X = X / len;
			Y = Y / len;
		}

		public void Rotate (double angle)
		{
			double rx = Math.Cos(angle)*X-Math.Sin(angle)*Y;
			Y = Math.Sin(angle)*X+Math.Cos(angle)*Y;
			X = rx;
		}

		public double Angle
		{
			get
			{
				double atan = Math.Atan(Y/X);
				if (atan < 0)
					atan = Math.PI * 2 + atan;
				if (X < 0)
					atan += Math.PI;
				return atan % (Math.PI * 2) ;
			}
		}

		public double AngleBetween (Vector2D v)
		{
			return AngleBetween (this, v);
		}

		public static double AngleBetween (Vector2D v1, Vector2D v2)
		{
			double val = Dot (v1, v2) / (v1.Length * v2.Length);
			val = Math.Acos (val);
			if (double.IsNaN(val))
				val = 0.0;
			if (!Right (v1, v2))
				return -val;
			return val;
		}

		static bool Right (Vector2D v1, Vector2D v2)
		{
			return (v1.X * v2.Y - v1.Y * v2.X) > 0;
		}

		public static double Dot (Vector2D v1, Vector2D v2)
		{
			return v1.X * v2.X + v1.Y * v2.Y;
		}

		public double Dot (Vector2D v)
		{
			return Dot (this, v);
		}


		public double Length 
		{
			get 
			{
				return Math.Sqrt (X * X + Y * Y);
			}
			set 
			{
				double lengthFactor = (Length/value);
				lengthFactor *= lengthFactor;
				X = Math.Sign(X) * Math.Sqrt( (X * X) / lengthFactor);
				Y = Math.Sign(Y) * Math.Sqrt( (Y * Y) / lengthFactor);
			}
		}

		public static double GetLength(double x, double y)
		{
			return Math.Sqrt (x * x + y * y);
		}

		public static Vector2D operator +(Vector2D left, Vector2D right)
		{
			return new Vector2D(left.X + right.X, left.Y + right.Y);
		}

		public static Vector2D operator -(Vector2D left, Vector2D right)
		{
			return new Vector2D(left.X - right.X, left.Y - right.Y);
		}

		public static Vector2D operator *(Vector2D vector, double mult)
		{
			return new Vector2D(vector.X * mult, vector.Y * mult);
		}

		public override string ToString ()
		{
			return String.Format ("v({0},{1})", X, Y);
		}
	}

}
